﻿using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class XEditorAnimationClipTab : XEditorAvatarTab
{
    AnimationClip targetClip;
    AnimationClip lastClip;
    
    string clipPath = string.Empty;
    string clipName = string.Empty;
    ModelImporter importer;
    SerializedObject serializedObject;
    SerializedProperty clipAnimations;
    XEditorAnimationClipInfoProperties clipInfoProperties;
    AnimationEvent[] events;
    AnimationEvent noneEvent;
    Vector2 scroll = Vector2.zero;
    int frameLength = 0;
    
    XAnimationAttackType eventAttackTypeAdd = XAnimationAttackType.None;
    XAnimationEventType eventTypeAdd = XAnimationEventType.None;
    bool ignoreEvenGen = false;
    Rect position = new Rect();

    public XEditorAnimationClipTab(EditorWindow window)
    {

    }

    public void OnEnable(Rect rect)
    {

    }

    public void OnDisable()
    {

    }

    public void OnReload()
    {

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static string GetFunctionName(XAnimationEventName type)
    {
        string name = string.Empty;
        switch (type)
        {
            case XAnimationEventName.Event:
                name = "OnAnimationEvent";
                break;
            case XAnimationEventName.AttackStart:
                name = "OnAnimationAttackStart";
                break;
            case XAnimationEventName.AttackEnd:
                name = "OnAnimationAttackEnd";
                break;
            case XAnimationEventName.AttackWarnStart:
                name = "OnAnimationAttackWarnStart";
                break;
            case XAnimationEventName.AttackWarnEnd:
                name = "OnAnimationAttackWarnEnd";
                break;
            case XAnimationEventName.Sound:
                name = "OnAnimationSound";
                break;
            case XAnimationEventName.Effect:
                name = "OnAnimationEffect";
                break;
            case XAnimationEventName.ForwardStart:
                name = "OnAnimationForwardStart";
                break;
            case XAnimationEventName.ForwardEnd:
                name = "OnAnimationForwardEnd";
                break;
            case XAnimationEventName.BackwardStart:
                name = "OnAnimationBackwardStart";
                break;
            case XAnimationEventName.BackwardEnd:
                name = "OnAnimationBackwardEnd";
                break;
            case XAnimationEventName.JumpStart:
                name = "OnAnimationJumpStart";
                break;
            case XAnimationEventName.JumpEnd:
                name = "OnAnimationJumpEnd";
                break;
        }
        return name;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static XAnimationEventName GetFunctionType(string name)
    {
        XAnimationEventName type = XAnimationEventName.None;
        switch (name)
        {
            case "OnAnimationEvent":
                type = XAnimationEventName.Event;
                break;
            case "OnAnimationAttackStart":
                type = XAnimationEventName.AttackStart;
                break;
            case "OnAnimationAttackEnd":
                type = XAnimationEventName.AttackEnd;
                break;
            case "OnAnimationAttackWarnStart":
                type = XAnimationEventName.AttackWarnStart;
                break;
            case "OnAnimationAttackWarnEnd":
                type = XAnimationEventName.AttackWarnEnd;
                break;
            case "OnAnimationSound":
                type = XAnimationEventName.Sound;
                break;
            case "OnAnimationEffect":
                type = XAnimationEventName.Effect;
                break;
            case "OnAnimationForwardStart":
                type = XAnimationEventName.ForwardStart;
                break;
            case "OnAnimationForwardEnd":
                type = XAnimationEventName.ForwardEnd;
                break;
            case "OnAnimationBackwardStart":
                type = XAnimationEventName.BackwardStart;
                break;
            case "OnAnimationBackwardEnd":
                type = XAnimationEventName.BackwardEnd;
                break;
            case "OnAnimationJumpStart":
                type = XAnimationEventName.JumpStart;
                break;
            case "OnAnimationJumpEnd":
                type = XAnimationEventName.JumpEnd;
                break;
        }

        return type;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="stringParameter"></param>
    /// <returns></returns>
    public static XAnimationEventType GetEventType(string stringParameter)
    {
        XAnimationEventType eventType = XAnimationEventType.None;
        string[] types = System.Enum.GetNames(typeof(XAnimationEventType));
        for (int i = 0; i < types.Length; i++)
        {
            if (types[i] == stringParameter)
            {
                eventType = (XAnimationEventType)i;
            }
        }

        return eventType;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="stringParameter"></param>
    /// <returns></returns>
    public static XAnimationAttackType GetEventAttackType(string stringParameter)
    {
        XAnimationAttackType eventType = XAnimationAttackType.None;
        string[] types = System.Enum.GetNames(typeof(XAnimationAttackType));
        for (int i = 0; i < types.Length; i++)
        {
            if (types[i] == stringParameter)
            {
                eventType = (XAnimationAttackType)i;
            }
        }
        return eventType;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static Color SetColor(XAnimationEventName name)
    {
        Color color = Color.white;
        switch (name)
        {
            case XAnimationEventName.AttackWarnStart:
            case XAnimationEventName.AttackWarnEnd:
                color = Color.yellow;
                break;
            case XAnimationEventName.AttackStart:
            case XAnimationEventName.AttackEnd:
                color = Color.red;
                break;
            case XAnimationEventName.Event:
                color = new Color(0.62f, 0.84f, 1.0f); ;
                break;
            case XAnimationEventName.Effect:
                color = Color.cyan;
                break;
            case XAnimationEventName.Sound:
                color = Color.gray;
                break;

            case XAnimationEventName.ForwardStart:
            case XAnimationEventName.ForwardEnd:
            case XAnimationEventName.BackwardStart:
            case XAnimationEventName.BackwardEnd:
            case XAnimationEventName.JumpStart:
            case XAnimationEventName.JumpEnd:
                color = Color.green;
                break;
            default:
                color = Color.white;
                break;
        }
        color.a = 1f;
        return color;
    }

    bool UpdateTargetClip()
    {
        if (lastClip != targetClip || serializedObject == null)
        {
            Selection.activeObject = targetClip;

            clipPath = AssetDatabase.GetAssetPath(targetClip);
            if (!string.IsNullOrEmpty(clipPath))
            {
                importer = AssetImporter.GetAtPath(clipPath) as ModelImporter;
                if (!importer)
                    return false;

                serializedObject = new SerializedObject(importer);

                clipAnimations = serializedObject.FindProperty("m_ClipAnimations");
                if (!clipAnimations.isArray || clipAnimations.arraySize < 1)
                {
                    return false;
                }
            }

            lastClip = targetClip;
            events = null;
        }

        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    void InitClipEvents()
    {
        if (events == null)
        {
            clipInfoProperties = new XEditorAnimationClipInfoProperties(clipAnimations.GetArrayElementAtIndex(0));
            events = AnimationUtility.GetAnimationEvents(targetClip);

            List<AnimationEvent> pvps = new List<AnimationEvent>();
            foreach (AnimationEvent e in events)
            {
                pvps.Add(e);
            }

            events = pvps.ToArray();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    bool DrawClipInfo()
    {
        if (string.IsNullOrEmpty(clipPath))
            return false;

        string[] names = clipPath.Split('/');
        clipName = names[names.Length - 1];

        EditorGUILayout.LabelField("Animation Clip Name", clipName);

        frameLength = (int)(targetClip.length * targetClip.frameRate);
        EditorGUILayout.LabelField("Animation Length", frameLength.ToString());

        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="evt"></param>
    /// <param name="idx"></param>
    /// <returns></returns>
    bool DrawEvent(AnimationEvent evt, int idx)
    {
        int areaW = (int)(position.width - 20);
        int areaH = (int)(position.height - 20);

        EditorGUILayout.BeginHorizontal();
        XAnimationEventName funcName = GetFunctionType(evt.functionName);
        GUI.backgroundColor = SetColor(funcName);

        funcName = (XAnimationEventName)EditorGUILayout.EnumPopup(funcName, GUILayout.Width(100));
        evt.functionName = GetFunctionName(funcName);
        evt.floatParameter = EditorGUILayout.FloatField(evt.floatParameter, GUILayout.Width(areaW * 0.1f));
        evt.intParameter = EditorGUILayout.IntField(evt.intParameter, GUILayout.Width(areaW * 0.1f));

        if (funcName == XAnimationEventName.AttackStart || funcName == XAnimationEventName.AttackWarnStart)
        {
            if (targetClip)
                evt.stringParameter = targetClip.name;

            evt.stringParameter = EditorGUILayout.TextField(evt.stringParameter, GUILayout.Width(areaW * 0.2f));
        }
        else if (funcName == XAnimationEventName.Event)
        {
            GUILayout.BeginHorizontal();
            float sacle = evt.objectReferenceParameter ? 0.2f : 0.1f;
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(XEventFrameObject), false, GUILayout.Width(areaW * sacle));
            if (!evt.objectReferenceParameter)
            {
                if (GUILayout.Button("+", GUILayout.Width(areaW * 0.1f)))
                {
                    string savePath = GetSavePath(targetClip, clipPath, "Event", typeof(XEventFrameObject));

                    XEventFrameObject eventFrame = ScriptableObject.CreateInstance<XEventFrameObject>();
                    eventFrame.attackName = targetClip.name;
                    eventFrame.path = savePath;

                    AssetDatabase.CreateAsset(eventFrame, savePath);
                    AssetDatabase.Refresh();

                    evt.objectReferenceParameter = AssetDatabase.LoadAssetAtPath<XEventFrameObject>(savePath);

                    EditorUtility.SetDirty(eventFrame);
                    AssetDatabase.SaveAssets();
                }
            }

            GUILayout.EndHorizontal();
        }
        else
        {
            evt.stringParameter = EditorGUILayout.TextField(evt.stringParameter, GUILayout.Width(areaW * 0.2f));
        }

        if (funcName == XAnimationEventName.ForwardStart || funcName == XAnimationEventName.BackwardStart || funcName == XAnimationEventName.JumpStart)
        {
            DrawMoveCurve(evt, idx, funcName);
        }
        else if (funcName == XAnimationEventName.Sound)
        {
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(GameObject), false, GUILayout.Width(areaW * 0.2f));
        }
        else if (funcName == XAnimationEventName.Effect)
        {
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(XEffectConfigObject), false, GUILayout.Width(areaW * 0.2f));
        }
        else if (funcName == XAnimationEventName.AttackStart)
        {
            GUILayout.BeginHorizontal();
            float sacle = evt.objectReferenceParameter ? 0.2f : 0.1f;
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(XAttackFrameObject), false, GUILayout.Width(areaW * sacle));
            if (!evt.objectReferenceParameter)
            {
                if (GUILayout.Button("+", GUILayout.Width(areaW * 0.1f)))
                {
                    string savePath = GetSavePath(targetClip, clipPath, "Attack", typeof(XAttackFrameObject));

                    XAttackFrameObject checkPoint = ScriptableObject.CreateInstance<XAttackFrameObject>();
                    checkPoint.attackName = targetClip.name;

                    AssetDatabase.CreateAsset(checkPoint, savePath);
                    AssetDatabase.Refresh();

                    evt.objectReferenceParameter = AssetDatabase.LoadAssetAtPath<XAttackFrameObject>(savePath);

                    EditorUtility.SetDirty(checkPoint);
                    AssetDatabase.SaveAssets();
                }
            }

            GUILayout.EndHorizontal();

        }
        else if (funcName == XAnimationEventName.AttackWarnStart)
        {
            GUILayout.BeginHorizontal();

            float sacle = evt.objectReferenceParameter ? 0.2f : 0.1f;
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(XAttackWarnFrameObject), false, GUILayout.Width(areaW * sacle));
            if (!evt.objectReferenceParameter)
            {
                if (GUILayout.Button("+", GUILayout.Width(areaW * 0.1f)))
                {
                    string savePath = GetSavePath(targetClip, clipPath, "Warn", typeof(XAttackWarnFrameObject));

                    XAttackWarnFrameObject checkPoint = ScriptableObject.CreateInstance<XAttackWarnFrameObject>();
                    checkPoint.attackName = targetClip.name;
                    
                    AssetDatabase.CreateAsset(checkPoint, savePath);
                    AssetDatabase.Refresh();

                    evt.objectReferenceParameter = AssetDatabase.LoadAssetAtPath<XAttackWarnFrameObject>(savePath);

                    EditorUtility.SetDirty(checkPoint);
                    AssetDatabase.SaveAssets();
                }
            }

            GUILayout.EndHorizontal();
        }
        else
        {
            evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(UnityEngine.Object), false, GUILayout.Width(areaW * 0.2f));
        }

        float f = (float)System.Math.Round((double)(evt.time / targetClip.length * 100f), 2);
        evt.time = EditorGUILayout.FloatField(f) * targetClip.length / 100f;
        GUI.backgroundColor = new Color(1.0f, 1.0f, 1.0f);

        EditorGUILayout.EndHorizontal();
        return true;
    }

    public bool DrawMoveCurve(AnimationEvent evt, int idx, XAnimationEventName funcName)
    {
        int areaW = (int)(position.width - 20);
        int areaH = (int)(position.height - 20);

        GUILayout.BeginHorizontal();
        float objscale = evt.objectReferenceParameter ? 0.15f : 0.1f;
        evt.objectReferenceParameter = EditorGUILayout.ObjectField(evt.objectReferenceParameter, typeof(XMoveCurveObject), false, GUILayout.Width(areaW * objscale));

        float scale = 0.1f;
        if (evt.objectReferenceParameter)
        {
            XMoveCurveObject moveCurve = AssetDatabase.LoadAssetAtPath<XMoveCurveObject>(AssetDatabase.GetAssetPath(evt.objectReferenceParameter.GetInstanceID()));
            if (moveCurve)
            {
                AnimationCurve curve = moveCurve.curve;

                float endtime = 0;
                switch (funcName)
                {
                    case XAnimationEventName.ForwardStart:
                        for (int x = 0; x < events.Length; x++)
                        {
                            if (events[x].functionName == GetFunctionName(XAnimationEventName.ForwardEnd))
                            {
                                if (evt.intParameter == events[x].intParameter)
                                {
                                    endtime = events[x].time;
                                }
                            }
                        }
                        break;
                    case XAnimationEventName.BackwardStart:
                        for (int x = 0; x < events.Length; x++)
                        {
                            if (events[x].functionName == GetFunctionName(XAnimationEventName.BackwardEnd))
                            {
                                if (evt.intParameter == events[x].intParameter)
                                {
                                    endtime = events[x].time;
                                    break;
                                }
                            }
                        }
                        break;
                    case XAnimationEventName.JumpStart:
                        for (int x = 0; x < events.Length; x++)
                        {
                            if (events[x].functionName == GetFunctionName(XAnimationEventName.JumpEnd))
                            {
                                endtime = events[x].time;
                                break;
                            }
                        }
                        break;
                }
                scale = 0.045f;
                moveCurve.curve = EditorGUILayout.CurveField(moveCurve.curve, GUILayout.Width(areaW * scale));

                evt.floatParameter = endtime;
                moveCurve.endTime = endtime;
                moveCurve.curve = curve;
                evt.objectReferenceParameter = moveCurve;

                EditorUtility.SetDirty(moveCurve);
            }
        }
        else
        {
            if (GUILayout.Button("+", GUILayout.Width(areaW * scale)))
            {
                string savePath = GetSavePath(targetClip, clipPath, "MoveCurve", typeof(XMoveCurveObject));

                XMoveCurveObject curveObj = ScriptableObject.CreateInstance<XMoveCurveObject>();
                AssetDatabase.CreateAsset(curveObj, savePath);
                AssetDatabase.Refresh();

                evt.objectReferenceParameter = AssetDatabase.LoadAssetAtPath<XMoveCurveObject>(savePath);

                EditorUtility.SetDirty(curveObj);
                AssetDatabase.SaveAssets();
            }
        }

        GUILayout.EndHorizontal();
        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="clip"></param>
    /// <param name="clipPath"></param>
    /// <param name="folder"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    public static string GetSavePath(AnimationClip clip, string clipPath, string folder, System.Type type)
    {
        string[] assetPaths = clipPath.Split(new string[] { "/" }, System.StringSplitOptions.RemoveEmptyEntries);
        string assetPath = string.Concat(assetPaths[1], "/", assetPaths[2], "/", assetPaths[3], "/EventObject/" + folder);

        string dirPath = Path.Combine(Application.dataPath, assetPath);
        if (!Directory.Exists(dirPath))
        {
            Directory.CreateDirectory(dirPath);
        }

        string assetName = Path.GetFileNameWithoutExtension(clipPath).Replace("@", "_").ToLower();
        int counter = 1;
        string savePath = "Assets/" + assetPath + "/" + assetName + ".asset";
        while (AssetDatabase.LoadAssetAtPath(savePath, type))
        {
            savePath = "Assets/" + assetPath + "/" + clip.name + counter.ToString() + ".asset";
            counter++;
        }

        return savePath;
    }

    void ProcessEventCount(AnimationEvent[] events)
    {
        int evtIndex = 0;
        foreach (AnimationEvent aniEvent in events)
        {
            if (GetFunctionType(aniEvent.functionName) == XAnimationEventName.Event)
            {
                aniEvent.intParameter = evtIndex;
                evtIndex++;
            }
        }
    }

    void ProcessAttackDamageCount(AnimationEvent[] events)
    {
        int dmgTotal = 0;
        foreach (AnimationEvent aniEvent in events)
        {
            if (GetFunctionType(aniEvent.functionName) == XAnimationEventName.AttackStart)
            {
                XAttackFrameObject checkPoint = aniEvent.objectReferenceParameter as XAttackFrameObject;
                dmgTotal++;
            }
        }

        int dmgCurrent = 1;
        foreach (AnimationEvent aniEvent in events)
        {
            if (GetFunctionType(aniEvent.functionName) == XAnimationEventName.AttackStart)
            {
                aniEvent.intParameter = dmgTotal;
                if (dmgTotal > 1)
                    aniEvent.floatParameter = dmgCurrent + 1.0f / dmgTotal;
                else
                    aniEvent.floatParameter = (float)dmgCurrent;

                XAttackFrameObject checkPoint = aniEvent.objectReferenceParameter as XAttackFrameObject;
                dmgCurrent++;
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="idx"></param>
    /// <returns></returns>
    bool DrawAddEvent()
    {
        int areaW = (int)(position.width - 20);
        int areaH = (int)(position.height - 20);

        GUI.color = SetColor(XAnimationEventName.None);
        EditorGUILayout.BeginHorizontal("box");
        EditorGUILayout.LabelField("", GUILayout.Width(20));
        EditorGUILayout.LabelField("Function Name", GUILayout.Width(100));
        EditorGUILayout.LabelField("Float", GUILayout.Width(areaW * 0.1f));
        EditorGUILayout.LabelField("Int", GUILayout.Width(areaW * 0.1f));
        EditorGUILayout.LabelField("String", GUILayout.Width(areaW * 0.2f));
        EditorGUILayout.LabelField("Object", GUILayout.Width(areaW * 0.2f));
        EditorGUILayout.LabelField("Time");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        if (noneEvent == null)
        {
            noneEvent = new AnimationEvent();
        }

        XAnimationEventName noneFuncName = (XAnimationEventName)EditorGUILayout.EnumPopup(GetFunctionType(noneEvent.functionName), GUILayout.Width(100));

        noneEvent.functionName = GetFunctionName(noneFuncName);
        noneEvent.floatParameter = EditorGUILayout.FloatField(noneEvent.floatParameter, GUILayout.Width(areaW * 0.1f));
        noneEvent.intParameter = EditorGUILayout.IntField(noneEvent.intParameter, GUILayout.Width(areaW * 0.1f));

        if (noneFuncName == XAnimationEventName.AttackStart)
        {
            eventAttackTypeAdd = (XAnimationAttackType)EditorGUILayout.EnumPopup(eventAttackTypeAdd, GUILayout.Width(areaW * 0.2f));
            if (eventAttackTypeAdd != XAnimationAttackType.None)
                noneEvent.stringParameter = eventAttackTypeAdd.ToString();
            else
                noneEvent.stringParameter = string.Empty;
        }
        else
        {
            eventTypeAdd = (XAnimationEventType)EditorGUILayout.EnumPopup(eventTypeAdd, GUILayout.Width(areaW * 0.2f));
            if (eventTypeAdd != XAnimationEventType.None)
                noneEvent.stringParameter = eventTypeAdd.ToString();
            else
                noneEvent.stringParameter = string.Empty;
        }

        noneEvent.objectReferenceParameter = EditorGUILayout.ObjectField("", noneEvent.objectReferenceParameter,
            typeof(UnityEngine.Object), false, GUILayout.Width(areaW * 0.2f));
        noneEvent.time = EditorGUILayout.FloatField(noneEvent.time / targetClip.length * 100f) * targetClip.length / 100f;
        EditorGUILayout.EndHorizontal();

        if (GUILayout.Button("Add"))
        {
            if (noneFuncName == XAnimationEventName.None)
                return false;

            List<AnimationEvent> tempList = new List<AnimationEvent>(targetClip.events);

            AnimationEvent newEvent = new AnimationEvent();
            newEvent.functionName = noneEvent.functionName.Trim();
            newEvent.floatParameter = noneEvent.floatParameter;
            newEvent.intParameter = noneEvent.intParameter;
            newEvent.stringParameter = noneEvent.stringParameter.Trim();
            newEvent.objectReferenceParameter = noneEvent.objectReferenceParameter;
            newEvent.time = (float)(noneEvent.time / targetClip.length * 100f) * targetClip.length / 100f;

            tempList.Add(newEvent);

            AnimationEvent[] array = new AnimationEvent[tempList.Count];
            for (int i = 0; i < tempList.Count; i++)
            {
                if (tempList[i] != null)
                {
                    array[i] = new AnimationEvent();
                    array[i].functionName = tempList[i].functionName.Trim();
                    array[i].floatParameter = tempList[i].floatParameter;
                    array[i].intParameter = tempList[i].intParameter;
                    array[i].stringParameter = tempList[i].stringParameter.Trim();
                    array[i].objectReferenceParameter = tempList[i].objectReferenceParameter;
                    array[i].time = tempList[i].time / targetClip.length;
                }
            }

            clipInfoProperties = new XEditorAnimationClipInfoProperties(clipAnimations.GetArrayElementAtIndex(0));
            clipInfoProperties.SetEvents(array);

            serializedObject.ApplyModifiedProperties();
            AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(targetClip));

            noneEvent = null;
            eventTypeAdd = XAnimationEventType.None;
            eventAttackTypeAdd = XAnimationAttackType.None;

            lastClip = null;
            events = null;
        }

        return false;
    }

    bool DrawRemoveEvent(int idx)
    {
        if (GUILayout.Button("-", GUILayout.Width(20), GUILayout.Height(14)))
        {
            List<AnimationEvent> list = new List<AnimationEvent>(events);
            list.RemoveAt(idx);

            AnimationEvent[] newEvents = new AnimationEvent[list.Count];
            for (int ix = 0; ix < list.Count; ix++)
            {
                if (list[ix] != null)
                {
                    newEvents[ix] = new AnimationEvent();
                    newEvents[ix].functionName = list[ix].functionName.Trim();
                    newEvents[ix].floatParameter = list[ix].floatParameter;
                    newEvents[ix].intParameter = list[ix].intParameter;
                    newEvents[ix].stringParameter = list[ix].stringParameter.Trim();
                    newEvents[ix].objectReferenceParameter = list[ix].objectReferenceParameter;
                    newEvents[ix].time = list[ix].time / targetClip.length;
                }
            }

            clipInfoProperties.SetEvents(newEvents);
            serializedObject.ApplyModifiedProperties();
            AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(targetClip));

            lastClip = null;
            events = null;

            return true;
        }

        return false;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    bool DrawAllEvent()
    {
        int areaW = (int)(position.width - 20);
        int areaH = (int)(position.height - 20);
        EditorGUILayout.BeginHorizontal("box");
        EditorGUILayout.LabelField("", GUILayout.Width(20));
        EditorGUILayout.LabelField("Function Name", GUILayout.Width(100));
        EditorGUILayout.LabelField("Float", GUILayout.Width(areaW * 0.1f));
        EditorGUILayout.LabelField("Int", GUILayout.Width(areaW * 0.1f));
        EditorGUILayout.LabelField("String", GUILayout.Width(areaW * 0.2f));
        EditorGUILayout.LabelField("Object", GUILayout.Width(areaW * 0.2f));
        EditorGUILayout.LabelField("Time");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginVertical("box");
        for (int idx = 0; idx < events.Length; idx++)
        {
            GUILayout.BeginHorizontal(GUILayout.Height(25));
            if (DrawRemoveEvent(idx))
            {
                GUILayout.EndHorizontal();
                return false;
            }

            DrawEvent(events[idx], idx);
            GUILayout.EndHorizontal();
        }
        EditorGUILayout.EndVertical();

        return true;
    }

    void SaveApply()
    {
        if (events != null)
        {
            ProcessEventCount(events);

            List<AnimationEvent> newEvents = new List<AnimationEvent>();
            for (int i = 0; i < events.Length; i++)
            {
                if (events[i] != null)
                {
                    if (GetFunctionType(events[i].functionName) != XAnimationEventName.None)
                    {
                        AnimationEvent nes = new AnimationEvent();
                        nes.functionName = events[i].functionName.Trim();
                        if (nes.functionName == XAnimationEventName.Event.ToString())
                        {
                            nes.intParameter = i;
                        }
                        else
                        {
                            nes.intParameter = events[i].intParameter;
                        }

                        nes.floatParameter = events[i].floatParameter;
                        nes.stringParameter = events[i].stringParameter.Trim();
                        nes.objectReferenceParameter = events[i].objectReferenceParameter;
                        nes.time = CalFixedEventTime(events[i].time, targetClip, frameLength) / targetClip.length;

                        newEvents.Add(nes);
                    }
                }
            }

            AssetDatabase.SaveAssets();

            if (clipAnimations == null)
            {
                clipAnimations = serializedObject.FindProperty("m_ClipAnimations");
            }

            clipInfoProperties = new XEditorAnimationClipInfoProperties(clipAnimations.GetArrayElementAtIndex(0));
            clipInfoProperties.SetEvents(newEvents.ToArray());
            serializedObject.ApplyModifiedProperties();

            string targetClipPath = AssetDatabase.GetAssetPath(targetClip);
            AssetDatabase.ImportAsset(targetClipPath);

            lastClip = null;
            events = null;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    bool ApplyEvents()
    {
        if (GUILayout.Button("Update"))
        {
            lastClip = null;
        }

        if (GUILayout.Button("Apply"))
        {
            SaveApply();
        }

        return true;
    }

    public static float CalFixedEventTime(float time, AnimationClip targetClip, int frameLength)
    {
        int countRate = (int)(time / targetClip.length * frameLength);
        float half = (countRate == frameLength || time == 0) ? 0f : 0.5f;
        float timeFixed = ((float)countRate + half) * targetClip.length / frameLength;

        return timeFixed;
    }

    public bool CopyKeyFrame(AnimationClip source, AnimationClip target)
    {
        if (!source && !target)
            return false;


        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    public void OnGUI(Rect windowPosition)
    {
        position = windowPosition;
        targetClip = EditorGUILayout.ObjectField("Target", targetClip, typeof(AnimationClip), true) as AnimationClip;
        if (targetClip)
        {
            ignoreEvenGen = EditorGUILayout.Toggle("ignoreEvenGen", ignoreEvenGen);
            if (!UpdateTargetClip())
                return;

            DrawClipInfo();
            InitClipEvents();

            GUILayout.Space(10);
            scroll = EditorGUILayout.BeginScrollView(scroll);

            DrawAllEvent();

            EditorGUILayout.EndScrollView();
            DrawAddEvent();

            if (GUILayout.Button("Calculate Attack Damage Count"))
            {
                ProcessAttackDamageCount(events);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }

            ApplyEvents();
        }
    }
}